/*
 * Copyright (c) 2013-2018 上海汇数数据. All rights reserved.
 * @(#) Regions.java 2018-08-19 18:37
 */

package cn.jh.common.core.cn;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.Ordering;
import com.google.common.collect.TreeMultimap;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import static cn.jh.common.core.cn.RegionConstants.CITY_CODE_SUFFIX;
import static cn.jh.common.core.cn.RegionConstants.STATE_CODE_SUFFIX;
import static cn.jh.common.core.cn.RegionConstants.listRegions;


/**
 * @author Fuchun
 * @since 1.0
 */
public class Regions {

    private static final RegionDataReader DATA_READER;

    static {
        RegionDataReader dataReader = new RegionDataReader();
        dataReader.initRegions();
        DATA_READER = dataReader;
    }

    /**
     * 检查给定的编号是否是省级行政区编号。
     *
     * @param code 要检查的编号。
     * @return 如果给定的编号是省级行政区编号，则返回{@code true}。否则{@code false}。
     */
    @Contract("null -> false")
    public static boolean isState(@Nullable String code) {
        return ruleMatch(code, STATE_CODE_SUFFIX) && DATA_READER.stateMap.containsKey(code);
    }

    /**
     * 检查给定的编号是否是地级行政区编号。
     *
     * @param code 要检查的编号。
     * @return 如果给定的编号是地级行政区编号，则返回{@code true}。否则{@code false}。
     */
    @Contract("null -> false")
    public static boolean isCity(@Nullable String code) {
        return ruleMatch(code, CITY_CODE_SUFFIX) && DATA_READER.cityMap.containsKey(code);
    }

    static boolean ruleMatch(@Nullable String code, String suffix) {
        return code != null && code.length() > 0 && code.endsWith(suffix);
    }

    @Nullable
    @Contract("null -> null")
    public static Region find(String code) {
        String c;
        if (code == null || (c = code.trim()).isEmpty()) {
            return null;
        }
        if (code.endsWith(STATE_CODE_SUFFIX)) {
            return DATA_READER.stateMap.get(c);
        } else if (code.endsWith(CITY_CODE_SUFFIX)) {
            return DATA_READER.cityMap.get(c);
        } else {
            return DATA_READER.countyMap.get(c);
        }
    }

    /**
     * 查找指定省（区）编号的下属所有城市（地区）信息。
     * <p />
     * 如果省（区）编号不存在，或不合法，则返回一个空(empty list)列表。
     *
     * @param stateCode 省（区）编号。
     * @return 返回指定省（区）编号的下属所有城市（地区）信息。
     */
    @NotNull
    public static List<Region> findCities(String stateCode) {
        if (!isState(stateCode)) {
            return ImmutableList.of();
        }
        Collection<String> cityCodes = DATA_READER.state2CityCodeMap.get(stateCode);
        if (cityCodes == null || cityCodes.isEmpty()) {
            return ImmutableList.of();
        }
        ImmutableList.Builder<Region> builder = ImmutableList.builder();
        for (String cityCode : cityCodes) {
            builder.add(DATA_READER.cityMap.get(cityCode));
        }
        return builder.build();
    }

    @NotNull
    public static List<Region> findCounties(String cityCode) {
        if (!isCity(cityCode)) {
            return ImmutableList.of();
        }
        Collection<String> countyCodes = DATA_READER.city2CountyCodeMap.get(cityCode);
        if (countyCodes == null || countyCodes.isEmpty()) {
            return ImmutableList.of();
        }
        ImmutableList.Builder<Region> builder = ImmutableList.builder();
        for (String countyCode : countyCodes) {
            builder.add(DATA_READER.countyMap.get(countyCode));
        }
        return builder.build();
    }

    /**
     * 返回一个不可变的，按照{@code Region::getCode} 顺序排序的一级行政区域列表信息{@code List<Region>}。
     */
    @NotNull
    public static List<Region> listState() {
        return listRegions(DATA_READER.stateMap.values());
    }

    /**
     * 返回一个不可变的，按照{@code Region::getCode} 顺序排序的二级行政区域列表信息{@code List<Region>}。
     */
    @NotNull
    public static List<Region> listCity() {
        return listRegions(DATA_READER.cityMap.values());
    }

    @NotNull
    public static Map<String, Collection<Region>> mapStateCode2Cities() {
        return parent2Regions(listCity());
    }

    /**
     * 返回一个不可变的，按照{@code Region::getCode} 顺序排序的三级行政区域列表信息{@code List<Region>}。
     */
    @NotNull
    public static List<Region> listCounty() {
        return listRegions(DATA_READER.countyMap.values());
    }

    public static Map<String, Collection<Region>> mapCityCode2Counties() {
        return parent2Regions(listCounty());
    }

    private static Map<String, Collection<Region>> parent2Regions(List<Region> regions) {
        TreeMultimap<String, Region> multimap = TreeMultimap.create(
                Ordering.natural(), RegionConstants.CODE_COMPARATOR);
        for (Region region : regions) {
            multimap.put(region.getParent(), region);
        }
        return multimap.asMap();
    }

    private Regions() {}
}
